﻿using System;
using System.Drawing;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;

namespace AppMain
{
    class SwMatrix
    {
        public static Mutex _updateInhibit = new Mutex();
        // tracks which transmitter is feeding each output of a switch
        // This is computed periodically for the display update based on the
        // information received from the PLC on switch position
        private static byte[] TxConnection = new byte[22];
        private static byte[] RealTxConnection = new byte[22];
        public static bool _registersChanged = false;
        public static short[] _dataToBeWritten = new short[4];
        // Switch Position Tracking. This can be either position 0, position 1
        // or position 255 (invalid)
        // updated in Modbus from PLC (Eventually)
        public const byte NumberOfSupportedSwitches = 10;
        public static byte[] _switchPositions = new byte[NumberOfSupportedSwitches];
        public static bool[] _switchError = new bool[NumberOfSupportedSwitches];
        public static bool[] _targetSwitchPositions = new bool[NumberOfSupportedSwitches];
        public static bool[] _workingTargetSwitchPositions = new bool[NumberOfSupportedSwitches];
        public static string[] _imageLocations = new string[NumberOfSupportedSwitches];
        public static bool[] _inhibitedTransmitters = new bool[NumberOfTransmitters];
        public static bool[] _unreadyAntennas = new bool[NumberOfAntennas+1];
        private static string[] _switchGraphicLocations =
        {
            "../../SwitchBoxInPosition0.png",
            "../../SwitchBoxInPosition1.png",
            "../../SwitchBoxToMoveToPosition0.png",
            "../../SwitchBoxToMoveToPosition1.png",
            "../../SwitchBoxInPositionFault.png",
            "../../SwitchBoxInPositionMoving.png"
        };
        public enum SwitchGraphic
        {
            Position0,
            Position1,
            ToPosition0,
            ToPosition1,
            PositionError,
            Moving,
        }
        public static bool _writeNewSwitchPositions = false;
        public static byte _lastAlternate = new byte();

        // Information for Updating Antenna Names
        public const byte NumberOfAntennas = 7;
        public const byte MaximumTransmitterNumber = 8;
        public const byte NumberOfTransmitters = 4;
        public static string[] _antennaNames =
        {
            "ANT1",
            "ANT2A",
            "ANT2B",
            "ANT3",
            "ANT4",
            "ANT5",
            "LOAD",
            "ANY"
        };

        public static bool[] _transmitterLocked =
        {
            false,
            false,
            false,
            false,
            false,
            false,
            false,
            false,
            false
        };


        // Information for computing Optimal Paths
        public enum SwitchCombinationFileError
        {
            NoError,
            BadFileName,
            BadTransmitterNumber,
            BadAntennaName,
            BadSwitchNumber,
            UnexpectedCharacter
        }

        private static List<byte[]>[][] _transmitterPaths = new List<byte[]>[MaximumTransmitterNumber + 1][];
        public static int _parseLineNumber = 0;
        private static List<byte[]> _sortedAlternates = new List<byte[]>();
        private static List<byte> _costTracking = new List<byte>();
        public static byte _configCost = new byte();
        public static bool _transferInitiated = false;
        public static bool _dataVerified = false;
        public static bool _transferActive = false;
        public static bool _aTransferWasActive = false;
        public static bool _transferSent = false;
        public static bool _transferComplete = true;
        public static bool _resetPressed = false;
        public static bool _swMatrixPlcCommLoss = false;

        // Information for updating Display on TxSwitcher
        public static Color[] _txColor = 
        {
            Color.Black,        // Disconnected
            Color.Black,        // TX1
            Color.Black,        // TX2
            Color.Black,        // TX3
            Color.Black,        // TX4
            Color.Green,        // TX5
            Color.Orange,       // TX6
            Color.Red,          // TX7
            Color.Blue          // TX8
        };

        public static byte _txSelected = 1;

        public static byte[] _antennaSelected = new byte[MaximumTransmitterNumber+1];
        public static byte[] _antennaConnected = new byte[MaximumTransmitterNumber+1];

        // Info log is configured even when a PLC connection doesn't exist so that
        // User input can be captured
        public static LogInfo _infoLog = AppMain.LogInfo.GetObject;

        public static void UpdateSwitchGraphicsLocations(SwitchGraphic graphic, string filename)
        {
            _switchGraphicLocations[(byte)graphic] = filename;

        }
        public static void CalculateTransmitterFeeds(byte[] switchPositions, byte[] actualPositions)
        {
            // track the current position to make copy/paste easier
            byte currentSwitch = 0;
            // Check Switch 1 Status
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 2 Status
            currentSwitch = 1;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 3 Status
            currentSwitch = 2;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 4 Status
            currentSwitch = 3;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 5 Status
            currentSwitch = 4;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 7 Status
            currentSwitch = 6;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 6 Status
            currentSwitch = 5;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 8 Status
            currentSwitch = 7;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 10 Status
            currentSwitch = 9;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
            // Check Switch 9 Status
            currentSwitch = 8;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                TxConnection[currentSwitch * 2] = TransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                TxConnection[currentSwitch * 2 + 1] = TransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
                // Image to Display
                if (switchPositions[currentSwitch] == actualPositions[currentSwitch])
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch]];
                }
                else
                {
                    _imageLocations[currentSwitch] = _switchGraphicLocations[(byte)switchPositions[currentSwitch] + 2];
                }
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                TxConnection[currentSwitch * 2] = 0;
                // Output B
                TxConnection[currentSwitch * 2 + 1] = 0;
                // Image to Display
                _imageLocations[currentSwitch] = _switchGraphicLocations[Convert.ToInt32(switchPositions[currentSwitch])];
            }
        }

        public static void CalculateRealTransmitterFeeds(byte[] switchPositions)
        {
            // track the current position to make copy/paste easier
            byte currentSwitch = 0;
            // Check Switch 1 Status
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 2 Status
            currentSwitch = 1;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 3 Status
            currentSwitch = 2;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 4 Status
            currentSwitch = 3;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 5 Status
            currentSwitch = 4;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 7 Status
            currentSwitch = 6;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 6 Status
            currentSwitch = 5;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 8 Status
            currentSwitch = 7;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 10 Status
            currentSwitch = 9;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Check Switch 9 Status
            currentSwitch = 8;
            // Valid Position
            if (switchPositions[currentSwitch] < (byte)SwitchGraphic.PositionError)
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = RealTransmitterFeedingSwitch(currentSwitch, switchPositions[currentSwitch]);
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = RealTransmitterFeedingSwitch(currentSwitch, (byte)(1 - (short)switchPositions[currentSwitch]));
            }
            // Invalid Position - outputs are not connected
            else
            {
                // Output A
                RealTxConnection[currentSwitch * 2] = 0;
                // Output B
                RealTxConnection[currentSwitch * 2 + 1] = 0;
            }
            // Figure out which Antenna is connected to which Transmitter
            for (byte x = 1; x <= MaximumTransmitterNumber; x++)
            {
                if (RealTxConnection[11] == x)
                {
                    _antennaConnected[x] = 0;
                }
                else if (RealTxConnection[15] == x)
                {
                    _antennaConnected[x] = 1;
                }
                else if (RealTxConnection[14] == x)
                {
                    _antennaConnected[x] = 2;
                }
                else if (RealTxConnection[17] == x)
                {
                    _antennaConnected[x] = 3;
                }
                else if (RealTxConnection[10] == x)
                {
                    _antennaConnected[x] = 4;
                }
                else if (RealTxConnection[18] == x)
                {
                    _antennaConnected[x] = 5;
                }
                else if (RealTxConnection[16] == x)
                {
                    _antennaConnected[x] = 6;
                }
                // transmitter is not connected to an antenna.
                else
                {
                    _antennaConnected[x] = NumberOfAntennas;
                }
            }
        }

        // return Transmitter connection data for each segment
        public static byte TransmitterFeedingSegment(byte Switch, byte segment)
        {
            return TxConnection[Switch * 2 + segment];
        }

        // return Transmitter connection data for each segment
        public static byte TransmitterFeedingSwitch(byte Switch, byte segment)
        {
            switch (segment)
            {
                case (byte)SwitchGraphic.Position0:
                {
                    switch (Switch)
                    {
                        case 0:
                        {
                            return 7;
                        }
                        case 1:
                        {
                            return 8;
                        }
                        case 2:
                        {
                            return TxConnection[3];
                        }
                        case 3:
                        {
                            return TxConnection[2];
                        }
                        case 4:
                        {
                            return TxConnection[6];
                        }
                        case 5:
                        {
                            return TxConnection[8];
                        }
                        case 6:
                        {
                            return TxConnection[7];
                        }
                        case 7:
                        {
                            return 0;
                        }
                        case 8:
                        {
                            return 0;
                        }
                        case 9:
                        {
                            return 0;
                        }
                        default:
                        {
                            return 0;
                        }
                    }
                }
                case (byte)SwitchGraphic.Position1:
                {
                    switch (Switch)
                    {
                        case 0:
                        {
                            return 5;
                        }
                        case 1:
                        {
                            return 6;
                        }
                        case 2:
                        {
                            return TxConnection[1];
                        }
                        case 3:
                        {
                            return TxConnection[4];
                        }
                        case 4:
                        {
                            return TxConnection[0];
                        }
                        case 5:
                        {
                            return TxConnection[12];
                        }
                        case 6:
                        {
                            return TxConnection[5];
                        }
                        case 7:
                        {
                            return TxConnection[9];
                        }
                        case 8:
                        {
                            return TxConnection[19];
                        }
                        case 9:
                        {
                            return TxConnection[13];
                        }
                        default:
                        {
                            return 0;
                        }
                    }
                }
                default:
                {
                    return 0;
                }
            } 
        }

        // return Transmitter connection data for each segment
        public static byte RealTransmitterFeedingSwitch(byte Switch, byte segment)
        {
            switch (segment)
            {
                case (byte)SwitchGraphic.Position0:
                {
                    switch (Switch)
                    {
                        case 0:
                        {
                            return 7;
                        }
                        case 1:
                        {
                            return 8;
                        }
                        case 2:
                        {
                            return RealTxConnection[3];
                        }
                        case 3:
                        {
                            return RealTxConnection[2];
                        }
                        case 4:
                        {
                            return RealTxConnection[6];
                        }
                        case 5:
                        {
                            return RealTxConnection[8];
                        }
                        case 6:
                        {
                            return RealTxConnection[7];
                        }
                        case 7:
                        {
                            return 0;
                        }
                        case 8:
                        {
                            return 0;
                        }
                        case 9:
                        {
                            return 0;
                        }
                        default:
                        {
                            return 0;
                        }
                    }
                }
                case (byte)SwitchGraphic.Position1:
                {
                    switch (Switch)
                    {
                        case 0:
                        {
                            return 5;
                        }
                        case 1:
                        {
                            return 6;
                        }
                        case 2:
                        {
                            return RealTxConnection[1];
                        }
                        case 3:
                        {
                            return RealTxConnection[4];
                        }
                        case 4:
                        {
                            return RealTxConnection[0];
                        }
                        case 5:
                        {
                            return RealTxConnection[12];
                        }
                        case 6:
                        {
                            return RealTxConnection[5];
                        }
                        case 7:
                        {
                            return RealTxConnection[9];
                        }
                        case 8:
                        {
                            return RealTxConnection[19];
                        }
                        case 9:
                        {
                            return RealTxConnection[13];
                        }
                        default:
                        {
                            return 0;
                        }
                    }
                }
                default:
                {
                    return 0;
                }
            }
        }

        // Load the Switch Combinations From the File
        public static SwitchCombinationFileError LoadSwitchCombinations(string fileName)
        {
            StreamReader _switchConfigFile;
            byte activeTransmitter = 0;
            byte oldActiveTransmitter = 0;
            byte activeAntenna = 0xFF;
            try
            {
                 _switchConfigFile = new StreamReader(fileName);
            }
            catch
            {
                return SwitchCombinationFileError.BadFileName;
            }
            _parseLineNumber = 0;
            while (!_switchConfigFile.EndOfStream)
            {
                string nextLine = _switchConfigFile.ReadLine();
                string[] columnArray = nextLine.Split(' ');
                //Track the line number on which the error occurred
                _parseLineNumber++;
                switch (columnArray[0])
                {
                    // Comment
                    case "//":
                    {
                        break;
                    }
                    // Indicates Which Switch Dictionary it should be placed into
                    case ":from":
                    {
                        activeAntenna = 0xFF;
                        string txText = columnArray[1].Substring(0, 2);
                        if(!txText.Equals("TX",StringComparison.CurrentCultureIgnoreCase))
                        {
                            return SwitchCombinationFileError.BadTransmitterNumber;
                        }
                        string txReference = columnArray[1].Substring(2);
                        try
                        {
                            activeTransmitter = Convert.ToByte(txReference);
                        }
                        catch
                        {
                            return SwitchCombinationFileError.BadTransmitterNumber;
                        }
                        if (activeTransmitter > MaximumTransmitterNumber)
                        {
                            return SwitchCombinationFileError.BadTransmitterNumber;
                        }
                        if (activeTransmitter != oldActiveTransmitter)
                        {
                            if (_transmitterPaths[oldActiveTransmitter] != null)
                            {
                                _transmitterPaths[oldActiveTransmitter][NumberOfAntennas] = new List<byte[]>();
                                _transmitterPaths[oldActiveTransmitter][NumberOfAntennas].Add(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });
                            }
                            _transmitterPaths[activeTransmitter] = new List<byte[]>[NumberOfAntennas+1];
                        }
                        oldActiveTransmitter = activeTransmitter;
                        if (columnArray[2] != ":to")
                        {
                            return SwitchCombinationFileError.UnexpectedCharacter;
                        }
                        string antText = columnArray[3];
                        // Catch The Any Case
                        for (byte x = 0; x < NumberOfAntennas + 1; x++)
                        {
                            // Use the Antenna Name Lookup, as the Antenna Names may change
                            if (_antennaNames[x].Contains(antText))
                            {
                                activeAntenna = x;
                                break;
                            }
                        }
                        // Antenna Not found
                        if (activeAntenna == 0xFF)
                        {
                            return SwitchCombinationFileError.BadAntennaName;
                        }
                        _transmitterPaths[activeTransmitter][activeAntenna] = new List<byte[]>();
                        break;
                    }
                    case ":cfg":
                    {
                        byte[] switchCfg =
                        {
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF,
                            0xFF
                        };
                        for (byte x = 1; x < 12; x++)
                        {
                            if (x >= columnArray.Length)
                            {
                                break;
                            }
                            byte activeSwitch = 0;
                            bool inverted = false;
                            string swText = "";
                            string swReference = "";
                            if (columnArray[x].Length < 1)
                            {
                                break;
                            }
                            string invert = columnArray[x].Substring(0, 1);
                            if (invert == "!")
                            {
                                inverted = true;
                                if (columnArray[x].Length < 3)
                                {
                                    break;
                                }
                                swText = columnArray[x].Substring(1, 2);
                                if (!swText.Equals("SW", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    return SwitchCombinationFileError.BadSwitchNumber;
                                }
                                swReference = columnArray[x].Substring(3, (columnArray[x].Length - 4));
                            }
                            else
                            {
                                inverted = false;
                                if (columnArray[x].Length < 2)
                                {
                                    break;
                                }
                                swText = columnArray[x].Substring(0, 2);
                                if (!swText.Equals("SW", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    return SwitchCombinationFileError.BadSwitchNumber;
                                }
                                swReference = columnArray[x].Substring(2, (columnArray[x].Length - 3));
                            }
                            string comma = columnArray[x].Substring((columnArray[x].Length - 1), 1);
                            if (comma != ",")
                            {
                                swReference += comma;
                            }
                            try
                            {
                                activeSwitch = Convert.ToByte(swReference);
                                if ((activeSwitch < 12) && (activeSwitch > 0))
                                {
                                    if (inverted)
                                    {
                                        switchCfg[activeSwitch-1] = 0;
                                    }
                                    else
                                    {
                                        switchCfg[activeSwitch-1] = 1;
                                    }
                                }
                            }
                            catch
                            {
                                return SwitchCombinationFileError.BadSwitchNumber;
                            }
                        }
                        _transmitterPaths[activeTransmitter][activeAntenna].Add(switchCfg);
                        break;
                    }
                    // empty space
                    default:
                    {
                        break;
                    }
                }
            }
            if (_transmitterPaths[oldActiveTransmitter] != null)
            {
                _transmitterPaths[oldActiveTransmitter][NumberOfAntennas] = new List<byte[]>();
                _transmitterPaths[oldActiveTransmitter][NumberOfAntennas].Add(new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF});
            }
            return SwitchCombinationFileError.NoError;
        }

        // Note: This function returns an optimal Switch Configuration based on the following Factors
        // Current configuration of the switches
        // Desired Antenna Connections
        // It updates a global array of boolean values which stores the intended switch configurations
        // In this way, individual channels can be locked after being modified.
        // This function is called from two places:
        // The Preview Button and
        // The Commit Button.
        // 
        // Note: This routine uses Brute Force and Ignorance to
        // determine which path is optimal. There are probably better ways to do this.
        //
        // Optimal Criteria:
        // No Locked paths are altered
        // Minimum number of switches must change position
        public static byte DetermineOptimalSwitchConfiguration()
        {
            List<byte[]> validConfigurations = new List<byte[]>();
            // This is where the locked Transmitters Control the seed to the
            // Valid connection calculations. This is handled by calling the
            // sort function, then checking both inputs on each transmitter.
            // If they are locked, they must remain what they are in the previous
            // configuration calculation.
            byte[] workingTargetSwitchPositions = new byte[NumberOfSupportedSwitches];
            for (byte x = 0; x < NumberOfSupportedSwitches; x++)
            {
                if(_workingTargetSwitchPositions[x])
                {
                    workingTargetSwitchPositions[x] = 1;
                }
                else
                {
                    workingTargetSwitchPositions[x] = 0;
                }

            }
            CalculateRealTransmitterFeeds(SwMatrix._switchPositions);
            // This is the seed fed into the iterative calculation below.
            // If a transmitter is locked, any switches that it feeds will
            // come into the calculation exactly as they are (or were).
            byte[] startingConfiguration = new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
            for (byte x = 0; x < NumberOfSupportedSwitches; x++)
            {
                // Handle Locked Transmitter logic. All configurations are forced to start with the
                // switches that a locked transmitter is feeding in their current position, inhibiting
                // any of the paths that would require changing them.
                if (_transmitterLocked[RealTransmitterFeedingSwitch(x, 0)] || _transmitterLocked[RealTransmitterFeedingSwitch(x, 1)])
                {
                    startingConfiguration[x] = _switchPositions[x];
                }
                // Remove all configurations that require the re-configuring of any
                // faulted switch
                if (_switchError[x])
                {
                    // Note, a switch in the moving position will inhibit any transfers that
                    // require use of this switch, the comparision can only occur between Position 0
                    // and Position 1 (so Error will always be false) this is intended operation, as
                    // the antennas feeding into a faulted switch will be inhibited anyway (this should
                    // allow re-routing around failed switches).
                    startingConfiguration[x] = _switchPositions[x];
                }
            }

            validConfigurations.Add(startingConfiguration);
            // Run for each transmitter to determine if there is a coincident
            // path to meet all antenna requirements
            for(byte x = 1;x <= MaximumTransmitterNumber; x++)
            {
                // skip unsupported transmitters
                if(_transmitterPaths[x] == null)
                {
                    continue;
                }

                AdditiveSwitchConfigurationBuilder(validConfigurations, x);
            }
            // Sort the Data to optimize the configurations based on the minimum Number
            // of Switches Moving.
            byte cost = 0, costIndex = 0;
            _sortedAlternates.Clear();
            _costTracking.Clear();
            foreach (byte[] switchCfg in validConfigurations)
            {
                cost = 0;
                for (byte x = 0; x < NumberOfSupportedSwitches; x++)
                {
                    if (_switchPositions[x] != switchCfg[x])
                    {
                        // invalid positions and Don't Cares don't contribute to the
                        // cost
                        if ((_switchPositions[x] != 0xFF) && (switchCfg[x] != 0xFF))
                        {
                            cost++;
                        }
                    }
                }
                costIndex = 0;
                while ((costIndex < _costTracking.Count) && (cost >= _costTracking[costIndex]))
                {
                    costIndex++;
                }
                _costTracking.Insert(costIndex, cost);
                _sortedAlternates.Insert(costIndex, switchCfg); 
            }
            
            if(_sortedAlternates.Count > 0)
            {
                return (byte)validConfigurations.Count;
            }
            return 0;
        }

        // This subroutine runs additively. It compares every entry in the dictionary to the configurations
        // which are required for the configuration for the antenna that it is considering
        // When this routine is complete, any configurations in the dictionary which conflict with
        // a configuration for this transmitter to connect to the specified antenna will be discarded.
        // any configuration which is still valid to connect to this antenna will be extended with any
        // optional paths which still provide a connection to the appropriate antenna.
        private static void AdditiveSwitchConfigurationBuilder(List<byte[]> input, byte transmitter)
        {
            // Note: Output Arrays must be stored to be added to the list when complete.
            // Although this seems strange, it is required.
            bool validConfig = true;
            byte[] output = new byte[NumberOfSupportedSwitches];
            
            List<byte[]> outputArrays = new List<byte[]>();
            byte antennaSelected = _antennaSelected[transmitter];
            // Avoid confusion on the "ANY" entrys on the Antenna Switcher
            // on the GUI.
            // There is one for each transmitter, but there is only one "ANY"
            // entry in the file.
            if (antennaSelected > NumberOfAntennas)
            {
                antennaSelected = NumberOfAntennas;
            }
            if (_transmitterPaths[transmitter][antennaSelected] != null)
            {
                foreach (byte[] config in _transmitterPaths[transmitter][antennaSelected])
                {
                    foreach (byte[] storedConfig in input)
                    {
                        validConfig = true;
                        for (byte x = 0; x < NumberOfSupportedSwitches; x++)
                        {
                            if (storedConfig[x] == config[x])
                            {
                                output[x] = config[x];
                            }
                            else
                            {
                                // This Transmitter Connection is a Don't Care
                                if (storedConfig[x] == 0xFF)
                                {
                                    output[x] = config[x];
                                }
                                // The incoming Connection is a Don't Care - note, if both
                                // Transmitter connection and incomming connection were Don't
                                // Cares, the execution would never get here, as the
                                // else statement above would be never be executed
                                else if (config[x] == 0xFF)
                                {
                                    output[x] = storedConfig[x];
                                }
                                else
                                {
                                    validConfig = false;
                                    break;
                                }
                            }
                        }
                        if (validConfig)
                        {
                            byte[] temp = new byte[NumberOfSupportedSwitches];
                            for (byte x = 0; x < NumberOfSupportedSwitches; x++)
                            {
                                temp[x] = output[x];
                            }
                            outputArrays.Add(temp);
                        }
                    }
                }
            }
            input.Clear();
            foreach (byte[] array in outputArrays)
            {
                input.Add(array);
            }
        }

        public static bool UpdateWorkingSwitchConfigWithAlternate(byte alternate)
        {
            // after the switch configuration builder routine has been called for each transmitter,
            // the dictionary will contain all valid paths to achieve the given configuration.
            // The other valid paths can be retrieved by requesting alternates
            if (_sortedAlternates.Count > alternate)
            {
                for (byte y = 0; y < NumberOfSupportedSwitches; y++)
                {
                    if (_sortedAlternates[alternate][y] == 0xFF)
                    {
                        if (_switchPositions[y] == 0)
                        {
                            _workingTargetSwitchPositions[y] = false;
                        }
                        // Note: invalid Switch position which is not configured
                        // in the active configuration will now be targeting position 1
                        else
                        {
                            _workingTargetSwitchPositions[y] = true;
                        }
                    }
                    else if (_sortedAlternates[alternate][y] == 1)
                    {
                        _workingTargetSwitchPositions[y] = true;
                    }
                    else
                    {
                        _workingTargetSwitchPositions[y] = false;
                    }
                }
                _configCost = _costTracking[alternate];
                return true;
            }
            return false;
        }
        public static void InitiateTransferSequence()
        {
            _transferInitiated = true;
            _dataVerified = false;
            _transferSent = false;
            _infoLog.Write("Switch Matrix GUI: Transfer Initiated");
        }
        public static void DetermineTransmittersToInhibit()
        {
            bool[] inhibitTransmitters = new bool[NumberOfTransmitters];
            for (byte x = 0; x < NumberOfSupportedSwitches; x++)
            {
                // Only look at the intended Transfer Switches if there is a transfer pending
                // or in progress.
                if (_transferInitiated || _transferActive)
                {
                    bool switchposition = false;
                    // Note, an invalid position will cause this to indicate Position B
                    // but this transmitter will already be inhibited by the logic below
                    if (_switchPositions[x] > 0)
                    {
                        switchposition = true;
                    }

                    // This switch is affected by the move.
                    if (switchposition != _targetSwitchPositions[x])
                    {
                        int index = (TransmitterFeedingSwitch(x, 0) + NumberOfTransmitters - MaximumTransmitterNumber - 1);
                        if (index >= 0 && index < NumberOfTransmitters)
                        {
                            inhibitTransmitters[index] = true;
                        }

                        index = (TransmitterFeedingSwitch(x, 1) + NumberOfTransmitters - MaximumTransmitterNumber - 1);
                        if (index >= 0 && index < NumberOfTransmitters)
                        {
                            inhibitTransmitters[index] = true;
                        }
                    }
                }

                // This Switch is in an invalid position
                if (_switchPositions[x] > (byte)SwitchGraphic.Position1)
                {
                    int index = (TransmitterFeedingSwitch(x, 0) + NumberOfTransmitters - MaximumTransmitterNumber - 1);
                    if (index >= 0 && index < NumberOfTransmitters)
                    {
                        inhibitTransmitters[index] = true;
                    }

                    index = (TransmitterFeedingSwitch(x, 1) + NumberOfTransmitters - MaximumTransmitterNumber - 1);
                    if (index >= 0 && index < 4)
                    {
                        inhibitTransmitters[index] = true;
                    }
                }
            }
            // The Antenna is not ready
            for (byte ant = 0; ant < NumberOfAntennas; ant++)
            {
                for (byte trx = 0; trx < NumberOfTransmitters; trx++)
                {
                    if (AppMain.SwMatrix._unreadyAntennas[ant])
                    {
                        if (TransmitterFeedingAntenna(ant) == trx + (MaximumTransmitterNumber - NumberOfTransmitters) + 1)
                        {
                            inhibitTransmitters[trx] = true;
                        }
                    }
                }
            }
            _inhibitedTransmitters = inhibitTransmitters;
        }
        public static int TransmitterFeedingAntenna(byte antenna)
        {
            switch (antenna)
            {
                case 0:
                {
                    return (TransmitterFeedingSegment(5, 1));
                }
                case 1:
                {
                    return (TransmitterFeedingSegment(7, 1));
                }
                case 2:
                {
                    return (TransmitterFeedingSegment(7, 0));
                }
                case 3:
                {
                    return (TransmitterFeedingSegment(8, 1));
                }
                case 4:
                {
                    return (TransmitterFeedingSegment(5, 0));
                }
                case 5:
                {
                    return (TransmitterFeedingSegment(9, 0));
                }
                case 6:
                {
                    return (TransmitterFeedingSegment(8, 0));
                }
                case 7:
                default:
                {
                    return 0;
                }
            }
        }
    }
}